const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser')
const fetch = require("node-fetch");
const crypto = require('crypto');


app.use(cookieParser());
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded

//模拟会话
const Sessions = {};
//首页
app.get('/', async function (req, res) {
    let sid = req.cookies.session_id;
    let s = Sessions[sid];
    //判断是否存在会话
    if (sid && s) {
        let user = s.user;
        //判断是否存用户信息
        if (!user) {
            //模拟通过token获取用户信息
            let data = await getuserinfo(req, res);
            console.log("test get:", data);
            if (data.data) user = s.user = data.data;
        }
        //存在用户信息则展示
        if (user) {
            return res.send(`<html> 
            <head>
            <meta charset="UTF-8">
            </head><h1>APP2</h1>
            <p>用户名:${user.name}</p>
            <p>真实姓名:${user.rname}</p>
            <p>邮箱:${user.mail}</p>
            <p>年龄:${user.age}</p>
            <a href="/login">退出</a></body>
            </html>`);
        }
    }
    return res.redirect('/login');
});

//login
app.get('/login', function (req, res) {
    let sid = req.cookies.session_id;
    if (sid) {
        let s = Sessions[sid];
        if (s) { delete s; };
        res.clearCookie('session_id', { domain: '.app2.com' });
    }
    res.write(`<html> 
    <head>
    <meta charset="UTF-8">
    </head><h1>APP2</h1><a href="/oauth/app1" target="_blank">通过(应用1)获取授权</a><br />
    <a href="/oauth/app2" target="_blank">通过(应用2)获取授权</a><br />
    <a href="/oauth/app3" target="_blank">通过(应用3)获取授权</a></body>
    </html>`);
    res.send();
});
//认证
app.get('/oauth/:id', function (req, res) {
    //根据自定义规则生成state示例
    let state = req.headers["user-agent"] + "_" + (+new Date());
    let md5 = crypto.createHash('md5');
    state = md5.update(state).digest('hex');
    //当然啦state可以存在session中
    res.cookie('state', state, { domain: '.app2.com' });
    // console.log(state);
    //根据参数判断请求认证的地址
    if (req.params.id == "app1") return res.redirect('http://app1.com:8081/oauth2/authorize?client_id=1881139527&redirect_uri=http%3A%2F%2Fapp2.com%3A8082%2Foauth_callback%2Fapp1&response_type=code&state=' + encodeURI(state));
    res.send('此应用未授权');
});
//认证回调 通过后台请求 token
const OauthCB = {
    "app1"(req, res) {
        //获取与解析参数
        let code = req.param('code');
        let state = req.param('state');
        state = decodeURI(state);
        res.clearCookie('state', { domain: '.app2.com' });
        //验证state是否一致
        if (state != req.cookies.state)
            return res.redirect('/oauth_fail?error=%E8%AE%A4%E8%AF%81%E5%A4%B1%E8%B4%A5');
        //通过后台发送相关信息来获取token
        fetch(`http://app1.com:8081/oauth2/token?grant_type=authorization_code&code=${code}&redirect_uri=http%3A%2F%2Fapp2.com%3A8082%2Foauth_callback%2Fapp1&client_id=1881139527`, {
            method: 'POST',
            // body: null,    
            redirect: 'follow', // set to `manual` to extract redirect headers, `error` to reject redirect 
            timeout: 10000,      //ms  
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Authorization': '623098a7c4018ae2f840b0d8763fb61732f1f7ce'//<====认证字符串或密钥
            }
        }).then(function (res) {
            console.log("Response Headers ============ ");
            res.headers.forEach(function (v, i, a) {
                console.log(i + " : " + v);
            });
            return res.json();
        }).then(function (data) {
            console.log("Response Body ============ ");
            console.log(data);
            //判断是否请求成功
            if (data.access_token) {
                //创建会话并记录token
                Sessions[state] = { token: data.access_token, oauth2: { url: "http://app1.com:8081", name: "app1" } };
                res.cookie('session_id', state, { domain: '.app2.com' });
            }
            res.redirect('/');
        }).catch(function (e) {
            console.log(e);
            res.redirect('/oauth_fail?error=' + e.toString());
        });
    },
    "app2"(req, res) {
        res.redirect('/oauth_fail?error=%E5%BA%94%E7%94%A8%E4%B8%8D%E5%AD%98%E5%9C%A8');
    }
};
app.get('/oauth_callback/:app', function (req, res) {
    let fun = OauthCB[req.params.app];
    if (fun) fun(req, res);
    else return res.redirect('/oauth_fail?error=%E5%BA%94%E7%94%A8%E4%B8%8D%E5%AD%98%E5%9C%A8');
});
//通过token获取用户信息
async function getuserinfo(req, res) {
    let sid = req.cookies.session_id;
    let s = Sessions[sid];
    //判断是否存在会话与认证服务器
    if (s && s.oauth2.name == "app1") {
        //请求数据 请求数据的参数根据情况添加
        return await fetch(`${s.oauth2.url}/user/getuserinfo?access_token=${s.token}`, {
            method: 'POST',
            // body: null,    
            redirect: 'follow', // set to `manual` to extract redirect headers, `error` to reject redirect 
            timeout: 100000,      //ms   
        }).then(function (res) {
            console.log("Response Headers ============ ");
            res.headers.forEach(function (v, i, a) {
                console.log(i + " : " + v);
            });
            return res.json();
        });
    }
};
//模拟失败提示页面
app.get('/oauth_fail', function (req, res) {
    let error = req.param('error');
    res.write(`<html> 
    <head>
    <meta charset="UTF-8">
    </head><h3>错误: ${error}</h3><a href="/login">返回登陆页面</a></body>
    </html>`);
    res.send();
});
app.listen(8082);
